package utilities;

import java.io.*;
import java.lang.reflect.Method;
import java.util.*;

public class Engine extends Thread {

	protected String name;
	protected BufferedWriter log;
	protected int debug = 0;
	protected List workQueue;
	protected Object configData;
	protected boolean active;
	protected int sleeps = 1000;
	protected boolean running = true;
	protected EngineCommander commander;
	
	public Engine()
	{}
	
	public void newEngine(String name, BufferedWriter log, List workQueue, 
			Object configData
			, int sleeps, int debug, EngineCommander commander)
	{
		this.name=name;
		this.log = log;
		this.workQueue = workQueue;
		this.configData = configData;
		this.sleeps = sleeps;
		this.debug=debug;
		this.commander=commander;
		this.processConfig();
	}
	
	public Engine(String name, BufferedWriter log, List workQueue, 
			Object configData
			, int sleeps, EngineCommander commander)
	{
		this.name=name;
		this.log = log;
		this.workQueue = workQueue;
		this.configData = configData;
		this.sleeps = sleeps;
		this.commander=commander;
		this.processConfig();
	}

	public EngineCommander getCommander()
	{
		return this.commander;
	}

	public void run()
	{
		try
		{
			Action action;
		active = true;
		int actSize = 0;
		while(running)
			{
				if(active)
				{
					//get all actions available, process each one
					actSize =workQueue.size();
					for(int i=0; i< actSize;i++)
					{
						//process each action
						 action = (Action) workQueue.get(i);
						 
						 log.write("Processing action: " + action.getActionDef().getName() + "\n");
						 
						 this.processAction(action);						
					}
					for(int i=0; i< actSize;i++)
					{
						//remove action
						workQueue.remove(0);
					}					
				}	
			this.sleep(sleeps);
			
			try
			{
				//if(debug==5)	log.write("    cycle \n");
			}catch(Exception ee) {}			
			
			}
		}
		catch(Exception e)
		{
			try
			{
			log.write("Thread died: " + name + "\n" + e.getMessage());
			}catch(Exception ee) {}
		}
	}

	protected void processAction(Action action)
	{
		ActionDef a = (ActionDef) action.getActionDef();
						
		try {
			if(debug>0)	log.write("prepping  " + a.getName() + "\n");
			Class [] pTypes = a.getParamTypes();
			String [] pNames = a.getParamNames();
			String [] pValues = action.getArgVals();
			Method meth = this.getClass().getMethod(a.getMethodName(), pTypes);
			
			Object argList[] = new Object[pNames.length];
			//must set values to these, ie cast on type
			
			for (int i=0;i<pNames.length; i++)
			{
				if(pTypes[0].equals(Integer.TYPE)) 
				{
					argList[i] = Integer.valueOf(pValues[i].toString()).intValue();
				}
				else if(pTypes[0].equals(String.class)) 
				{
					argList[i] = pValues[i];
				}
				else
				{
					//default to string
					argList[i] = pValues[i];					
				}
				
				
			}
			
			if(argList!=null)
			{
				if(argList.length>0)
				{
					if(debug>0)	log.write("running, arg 1=" + argList[0].toString() + "\n");					
				}
			}
			
			Object retobj = meth.invoke(this, argList);
			
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			try {
				e.printStackTrace(new PrintWriter(log));
				log.write("engine error " + e.getCause() + "\n\n");
				e.printStackTrace(new PrintWriter(log));
				
			} catch (Exception ee){}
		} catch (NoSuchMethodException e) {
			try {
				log.write("engine error " + e.getCause() + "\n\n");
				e.printStackTrace(new PrintWriter(log));
			} catch (Exception ee){}
		} catch (Exception e) {
			try {
				log.write("engine error " + e.getCause() + "\n\n");
				e.printStackTrace(new PrintWriter(log));
			} catch (Exception ee){}
		}				
	}
	private void processConfig()
	{}
	
	
	public void deActivate()
	{
		active = false;
	}
	public void activate()
	{
		active = true;
	}
	
	public void close()
	{
		
	}
	
	public int getSleeps() {return sleeps;}
	public void setSleeps(int sleeps)
	{
		this.sleeps = sleeps;
	}
	public boolean getActive() {return active;}
	
	public void setConfigData(Object configData)
	{
		this.configData = configData;
	}
	public Object getConfigData() {return configData;}
	
}
